﻿Задание Упрощённый markdown
----------------------------

# Общее описание

Требуется написать программу на языке С++, использующую парадигму ООП, отображающую на экране форматированный текст. 
В аргументах командной строки задаются параметры, влияющие на стиль отображения текста.

Для разбора параметов необходимо использовать функцию getopt или getopt_long Параметры указываются следующим 
образом:

1. -f имя файла с разметкой,
3. -t отступ для второй и последующих строк списка (число пробелов),
4. -m символ-маркер ненумерованного списка,
5. -r величина красной строки.
6. -h - выдача help с описанием поведения программы
7. -v - отображение версии программы

Здесь предполагается, что параметры по ключам -t,-m,-r - не обязательны и если параметр не указан, 
то задаётся значение по умолчанию.
Возможно например определение ширины экрана при помощи системных вызовов fstat и ioctl (man tty_ioctl).

# Описание форматов

Размеченый текст состоит из абзацев. Существует несколько типов абзацев: 

* заголовки,
* списки 
  1. нумерованные списки, 
  2. маркированные списки, 
* простые абзацы.

Абзацы отделяются друг от друга двумя и более переносами строк. Всюду внутри абзацев два пробельных 
символа подряд считаются одним пробелом.

Заголовок задаётся следующим образом:

\# Текст заголовка до конца строки

Заголовки могут быть нескольких уровней, уровень заголовка задаётся числом символов '#' подряд в начале.
Заголовок нулевого уровня задаётся строкой состоящей из минусов, которая подписывается после собственно 
заголовка.

Нумерованные списки (число перед точкой не играет роли):

100. первый элемент списка
200. второй элемент списка

Маркированный список задаётся по аналогии с нумерованным, используется символ '*'.

Списки могут быть вложены друг в друга, вложенный список задаётся указанием отступа в 2 пробела
от предыдущего уровня.

Блок кода. Блок кода начинается 4-мя пробелами, либо одним символом табуляции, 
далее идёт собственно код.

Простые абзацы это все остальные абзацы. Чаще всего они будут начинаться просто с текста.

Примером разметки является текст с заданием.

# Описание способа отображения

Для размеченного текста, в соответствии с параметрами функции main требуется задать отображение на экран.

При отображении на экран все пробельные символы между словами должны быть заменены на один пробел 
(в памяти хранить именно в таком виде). В случае, если текст не помещается на одну строку, в него 
вставляются переносы. Запрещается, чтобы текст с переносами вылезал за границу ширины текста,
также запрещается переносить так, чтобы на строчке оставался бы один символ. 
В случае невозможности поставить перенос строка завершается, а слово пишется на следующей строчке
(выдавать предупреждение и завершать программу если слово оказалось длиннее отображаемой ширины текста).

Для списков в начале ставится либо маркер, либо число c точкой, далее через определённое число пробельных символов, 
отсчитываемых от начала экрана, идёт текст связанный с элементом списка. Если элемент списка не помещается в одну строчку, 
то на следующих строчках так же ставятся пробельные символы так, чтобы был эффект отступа от края. 
Так продолжается до следующего элемента. На следующем элементе всё начинается по новой: мы ставим маркер 
или следующий номер в нумерации, пробельные символы и текст. 
Если список вложенный, то на каждую строчку ставится
дополнительный отступ в соответствии с уровнем вложенности.
Маркеры списков, и числа в нумерованных списках дополнительно должны быть помечены голубым цветом.

Заголовки отображаются по центру заданной ширины экрана. При этом заголовок заключается в коробочку из символов '#'. 
Коробочка ограничена справа и слева размерами отображаемой части окна терминала. 
Левая и правая граница коробочки обрамляется в столько решёточек, какого уровня заголовок, а сверху и снизу отображается 
на всю ширину экрана строка из решёток. После заголовка обязательно должна быть отображена пустая строка. 
Заголовки должны быть подсвечены жёлтым цветом.

Блок кода отображается таким образом, что строка начинается символом '@', далее 3 пробела и сам код, который никак 
не интерпретируется, и в случае выхода за границы экрана просто обрезается при отображении. Код должен быть подсвечен 
зелёным цветом.

Простые абзацы начинаются с отступа первой строки задаваемого числом пробелов. На остальных 
строках отступа уже нет. 

# Требования к программному коду

Программный код должен быть написан на C++ и содержать абстрактный базовый класс Abstract_text, 
который содержит следующие методы: 

    virtual unsigned long int count_symbols() const = 0;
    virtual unsigned long int count_words() const = 0;
    virtual int print(FILE *) const = 0;

Каждый логический элемент текста должен храниться как char* в наследнике класса Abstract_text. 
Запрещается использовать классы std::string и std::vector.

Каждый класс должен быть описан в собственном cpp файле и компилироваться в отдельный объектный модуль.

Требуется создать наследников данного класса, где каждый класс соответствует
одному из типов абзацев в размеченном тексте.
В наследниках необходимо полностью определить интерфейс
класса-родителя, реализация которого будет осуществлять 
параметризованную печать текста.

В программе должен быть класс Text_viewer, который  осуществляет чтение текста из файла 
и сохраняет его в хранилище во внутреннее для данного класса наследника представление (для списков например сохраняет порядковый номер элемента списка).  Класс должен предоставлять метод для распечатки 
на экран из хранилища. Хранилище текста - массив указателей на объекты Abstract_text.

После распечатки текста, в стандартный поток ошибок должно быть выведено число символов и число слов в исходном тексте,
при этом несколько идущих подряд пробельных символов являются одним символом и служебные символы задающие разметку 
не участвуют в подсчёте числа символов и слов.

В случае невозможности отображения текста программа должна выдавать сообщение об ошибки 
с вразумительным описанием проблемы.

Предусмотреть возможность перенаправления печати в файл, а не только в терминал, в этом случае ширину экрана нужно принять
равной 100 и отключить управление цветом (не печатать соответствующие управляющие символы).
